package com.lkd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.Lists;
import com.lkd.common.VMSystem;
import com.lkd.config.TopicConfig;
import com.lkd.contract.OrderCheck;
import com.lkd.contract.VendoutContract;
import com.lkd.contract.VendoutData;
import com.lkd.dao.OrderDao;
import com.lkd.emq.MqttProducer;
import com.lkd.entity.OrderEntity;
import com.lkd.exception.LogicException;
import com.lkd.feign.UserService;
import com.lkd.feign.VMService;
import com.lkd.service.OrderService;
import com.lkd.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    private RestHighLevelClient esClient;

    @Autowired
    private VMService vmService;

    @Autowired
    private UserService userService;

    @Autowired
    private MqttProducer mqttProducer;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public OrderEntity getByOrderNo(String orderNo) {
        QueryWrapper<OrderEntity> qw = new QueryWrapper<>();
        qw.lambda()
                .eq(OrderEntity::getOrderNo,orderNo);
        return this.getOne(qw);
    }


    @Override
    public Pager<OrderVO> search(Integer pageIndex, Integer pageSize, String orderNo, String openId, String startDate, String endDate) {
        return Pager.buildEmpty();
    }


    @Override
    public List<Long> getTop10Sku(Integer businessId) {

        SearchRequest searchRequest=new SearchRequest("order");
        SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
        //查询条件：最近三个月

        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("update_time");
        rangeQueryBuilder.gte( LocalDateTime.now().plusMonths(-3).format(  DateTimeFormatter.ISO_DATE_TIME )  );
        rangeQueryBuilder.lte( LocalDateTime.now().format(  DateTimeFormatter.ISO_DATE_TIME )  );

        BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery();
        boolQueryBuilder.must( rangeQueryBuilder );

        boolQueryBuilder.must( QueryBuilders.termQuery("business_id",businessId) );
        sourceBuilder.query(boolQueryBuilder);

        AggregationBuilder orderAgg = AggregationBuilders.terms("sku").field("sku_id")
                .subAggregation(AggregationBuilders.count("count").field("sku_id"))
                .order(BucketOrder.aggregation("count", false))
                .size(10);

        sourceBuilder.aggregation(orderAgg);
        searchRequest.source(sourceBuilder);

        try {
            SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            if(aggregations==null ) return  Lists.newArrayList();

            var term = (Terms)aggregations.get("sku");
            var buckets = term.getBuckets();

            return buckets.stream().map(  b->   Long.valueOf( b.getKey().toString() ) ).collect(Collectors.toList());

        } catch (IOException e) {
            e.printStackTrace();
            return Lists.newArrayList();
        }

    }

    /**
     * 创建订单
     * @param payVO
     */
    @Override
    public OrderEntity createOrder(PayVO payVO) {
        //创建分布式锁
        RLock lock = redissonClient.getLock(String.format(VMSystem.VM_LOCK_KEY_PREF, payVO.getInnerCode()));
        try {
            if (!lock.tryLock(0L, 2L, TimeUnit.MINUTES)){
                throw new LogicException("设备出货中，请稍后");
            }
        } catch (InterruptedException e) {
            log.error("设备出货异常");
        }
        //判断售货机中是否有库存
        String innerCode = payVO.getInnerCode();
        String skuId = payVO.getSkuId();
        String openId = payVO.getOpenId();

        Boolean hasCapacity = vmService.hasCapacity(innerCode, Long.parseLong(skuId));
        if (false == hasCapacity){
            throw new LogicException("商品无库存");
        }

        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderNo(innerCode+System.nanoTime());
        //支付流水号
        //orderEntity.setThirdNo();
        orderEntity.setInnerCode(innerCode);
        VmVO vmInfo = vmService.getVMInfo(innerCode);
        orderEntity.setAddr(vmInfo.getNodeAddr());
        orderEntity.setSkuId(Long.parseLong(skuId));
        orderEntity.setSkuName(vmService.getSku(skuId).getSkuName());
        //商品类别Id
        orderEntity.setClassId(vmService.getSku(skuId).getClassId());
        //订单状态
        orderEntity.setStatus(VMSystem.ORDER_STATUS_CREATE);
        //支付金额
        orderEntity.setAmount(vmService.getSku(skuId).getRealPrice());
        //分账金额

        PartnerVO partner = userService.getPartner(vmInfo.getOwnerId());
        Integer ratio = partner.getRatio();
        BigDecimal bigDecimal =  new BigDecimal(ratio);
        BigDecimal multiply = bigDecimal.multiply(new BigDecimal(vmService.getSku(skuId).getRealPrice()));
        orderEntity.setBill(Integer.parseInt(multiply.toString()));
        //商品金额
        orderEntity.setPrice(vmService.getSku(skuId).getPrice());
        orderEntity.setPayType("2");
        orderEntity.setPayStatus(VMSystem.PAY_STATUS_NOPAY);
        //点位Id
        long nodeId = vmInfo.getNodeId();
        orderEntity.setNodeId(nodeId);
        orderEntity.setNodeName(vmService.getNodeName(nodeId));
        orderEntity.setRegionId(vmInfo.getRegionId());
        orderEntity.setRegionName(vmInfo.getRegionName());
        orderEntity.setBusinessId(vmInfo.getBusinessId());
        orderEntity.setRegionName(vmInfo.getBusinessName());

        //合作商Id
        orderEntity.setOwnerId(partner.getId());
        //微信用户openId
        orderEntity.setOpenId(openId);

        //保存订单详情到数据库
        save(orderEntity);

        //协议封装: OrderCheck  封装的是订单号
        OrderCheck orderCheck = new OrderCheck();
        orderCheck.setInnerCode(orderEntity.getInnerCode());
        orderCheck.setOrderNo(orderEntity.getOrderNo());

        //发送到EMQ
        try {
            mqttProducer.send("$delayed/600/"+TopicConfig.ORDER_CHECK_TOPIC, 2, orderCheck);
        } catch (JsonProcessingException e) {
            log.error("发送支付超时异常");
        }

        return orderEntity;

    }

    /**
     * 出货
     * @param orderNo
     */
    @Override
    public void giveProduct(String orderNo) {
        //根据订单号查询订单
        OrderEntity orderEntity = getByOrderNo(orderNo);
        //更改支付状态为已支付，更改订单状态为已支付
        orderEntity.setStatus(VMSystem.ORDER_STATUS_PAYED);
        orderEntity.setPayStatus(VMSystem.PAY_STATUS_PAYED);
        updateById(orderEntity);
        //在出货方法中，封装出货协议，并发送到EMQ
        VendoutData vendoutData = new VendoutData();
        VendoutContract vendoutContract = new VendoutContract();

        vendoutData.setOrderNo(orderEntity.getOrderNo());
        vendoutData.setSkuId(orderEntity.getSkuId());

        vendoutContract.setVendoutData(vendoutData);

        try {
            mqttProducer.send(TopicConfig.VMS_VENDOUT_TOPIC, 2, vendoutContract);
        } catch (JsonProcessingException e) {
            throw new LogicException("发送出货出货协议失败");
        }
    }

}
